package com.onlyoffice.demo.onlyoffice.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.onlyoffice.demo.onlyoffice.domain.File;
import com.onlyoffice.demo.onlyoffice.domain.RenameFileReq;
import com.onlyoffice.demo.onlyoffice.mapper.FileMapper;
import com.onlyoffice.demo.onlyoffice.service.IFileService;
import com.onlyoffice.demo.onlyoffice.service.IUserService;
import com.onlyoffice.model.common.User;
import com.onlyoffice.model.documenteditor.Config;
import com.onlyoffice.model.documenteditor.config.Document;
import com.onlyoffice.model.documenteditor.config.EditorConfig;
import com.onlyoffice.model.documenteditor.config.document.DocumentType;
import com.onlyoffice.model.documenteditor.config.document.Info;
import com.onlyoffice.model.documenteditor.config.document.Permissions;
import com.onlyoffice.model.documenteditor.config.document.Type;
import com.onlyoffice.model.documenteditor.config.document.permissions.CommentGroups;
import com.onlyoffice.model.documenteditor.config.editorconfig.Customization;
import com.onlyoffice.model.documenteditor.config.editorconfig.Mode;
import com.onlyoffice.model.documenteditor.config.editorconfig.customization.Goback;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * 文件服务
 *
 * @author ZWX
 * @date 2025-07-09
 */
@Service
@Slf4j(topic = "File")
@RequiredArgsConstructor
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IFileService {

    @Value("${onlyoffice.uploadPath}")
    private String uploadPath;
    @Value("${onlyoffice.host-ip}")
    private String hostIp;
    @Value("${server.port}")
    private String port;
    @Value("${onlyoffice.callback-url}")
    private String callbackUrl;

    private final IUserService userService;

    /**
     * 上传文件
     *
     * @param file 文件
     * @return 结果
     */
    @Override
    public boolean uploadFile(MultipartFile file) {
        try (InputStream is = file.getInputStream()) {
            File fileDb = new File();
            fileDb.setFileId(IdUtil.getSnowflakeNextId());
            String originalFilename = file.getOriginalFilename();
            fileDb.setOriginalFileName(originalFilename);
            fileDb.setSuffix(FileUtil.getSuffix(originalFilename));
            int size = file.getBytes().length;
            fileDb.setSize((long) size);
            fileDb.setUploadTime(LocalDateTime.now());
            fileDb.setUploadUser("admin");
            String newFileName = UUID.randomUUID() + "." + fileDb.getSuffix();
            fileDb.setFileName(newFileName);
            fileDb.setUrl("http://" + hostIp + ":" + port + "/resources/" + newFileName);
            fileDb.setFileKey(IdUtil.simpleUUID());
            FileUtil.writeFromStream(is, uploadPath + "/" + newFileName);
            return save(fileDb);
        } catch (Exception e) {
            log.error("", e);
            return false;
        }
    }

    /**
     * 删除文件
     *
     * @param fileId 文件Id
     * @return 结果
     */
    @Override
    public boolean deleteFile(Long fileId) {
        File file = getById(fileId);
        if (Objects.isNull(file)) {
            throw new RuntimeException("文件不存在");
        }
        // 删除文件
        String filePath = uploadPath + "/" + file.getFileName();
        if (FileUtil.del(filePath)) {
            return removeById(fileId);
        } else {
            return false;
        }
    }

    /**
     * 重命名文件
     *
     * @param req 参数
     * @return 结果
     */
    @Override
    public boolean renameFile(RenameFileReq req) {
        File file = getById(req.getFileId());
        if (Objects.isNull(file)) {
            throw new RuntimeException("文件不存在");
        }
        file.setOriginalFileName(req.getNewFileName() + "." + file.getSuffix());
        return updateById(file);
    }

    /**
     * 获取Onlyoffice配置信息
     *
     * @param fileId 文件ID
     * @param mode   模式
     * @param userId 用户ID
     * @return Onlyoffice配置信息
     */
    @Override
    public Config getOnlyOfficeConfig(Long fileId, Mode mode, Long userId) {

        com.onlyoffice.demo.onlyoffice.domain.User currentUser = userService.getById(userId);
        if (Objects.isNull(currentUser)) {
            throw new RuntimeException("用户不存在");
        }

        File file = getById(fileId);
        if (Objects.isNull(file)) {
            throw new RuntimeException("文件不存在");
        }
        DocumentType documentType = null;
        String fileSuffix = file.getSuffix();
        if (Pattern.matches("docx|doc|txt|wps", fileSuffix)) {
            documentType = DocumentType.WORD;
        } else if (Pattern.matches("xlsx|xls", fileSuffix)) {
            documentType = DocumentType.CELL;
        } else if (Pattern.matches("pptx|ppt", fileSuffix)) {
            documentType = DocumentType.SLIDE;
        } else if (Pattern.matches("pdf", fileSuffix)) {
            documentType = DocumentType.PDF;
        } else {
            throw new RuntimeException(String.format("不支持的文件类型 %s", fileSuffix));
        }

        Info info = Info.builder()
                .favorite(false)
                .owner(file.getUploadUser())
                .uploaded(file.getUploadTime().toString())
                .build();

        Permissions permissions = Permissions.builder()
                .chat(false)
                .comment(true)
                .commentGroups(new CommentGroups())
                .copy(true)
                .download(true)
                .edit(true)
                .fillForms(true)
                .modifyContentControl(true)
                .modifyFilter(true)
                .print(true)
                .protect(true)
                .review(true)
                .reviewGroups(null)
                .userInfoGroups(null)
                .build();

        // TODO 处理reviewGroups，userInfoGroups
        if (Mode.EDIT.equals(mode)) {
            // 以编辑模式打开，需要设置reviewGroups，userInfoGroups

        }

        Document document = Document.builder()
                .key(file.getFileKey())
                .fileType(fileSuffix.replace(".", ""))
                .info(info)
                .permissions(permissions)
                .title(file.getOriginalFileName())
                .url(file.getUrl())
                .build();

        User user = User.builder()
                .id(currentUser.getUserId().toString())
                .name(currentUser.getUserName())
                .image(currentUser.getUserImage())
                .group(currentUser.getUserGroup())
                .build();

        Goback goback = Goback.builder()
                .url("")
                .build();

        Customization customization = Customization.builder()
                .autosave(true)
                .comments(true)
                .compactHeader(false)
                .compactToolbar(false)
                .forcesave(false)
                .help(true)
                .hideRightMenu(false)
                .hideRulers(false)
                .feedback(false)
                .goback(goback)
                .plugins(false)
                // .submitForm()
                .build();

        EditorConfig editorConfig = EditorConfig.builder()
                .createUrl(null)
                .lang("zh")
                .mode(mode)
                .user(user)
                .recent(null)
                .templates(null)
                .customization(customization)
                .plugins(null)
                .build();

        // 处理编辑回调
        if (Mode.EDIT.equals(mode)) {
            // 以编辑模式打开，需要设置回调地址
            editorConfig.setCallbackUrl(StrUtil.format("{}?fileId={}", callbackUrl, fileId));
        }

        return Config.builder()
                .height("100%")
                .width("100%")
                .type(Type.DESKTOP)
                .document(document)
                .documentType(documentType)
                .editorConfig(editorConfig)
                .build();
    }
}
